iT邦幫忙

2021 iThome 鐵人賽

DAY 22
1
Modern Web

Canvas 小錦囊系列 第 22

Day22 - 用 canvas 做 圈圈叉叉遊戲

  • 分享至 

  • xImage
  •  

前述

今天終於久違的真正完成了一個項目,一起來看看效果跟 code 吧!
我就直接在 code 裡註記 操作囉~

codesendBox

import { useEffect, useRef } from "react";
import "./styles.css";

let player = 1;
const lineColor = "#ddd";

const canvasSize = 500;
const sectionSize = canvasSize / 3;

export default function App() {
  const canvasRef = useRef(null);

  useEffect(() => {
    // 首次載入時,畫上井字線
    if (canvasRef.current) drawLines(10, lineColor);
  }, [canvasRef]);

  /**
   * 每次滑鼠點擊時,替換選手
   * @param {*} event
   */
  const handleMouseDown = (event) => {
    if (canvasRef.current) {
      if (player === 1) {
        player = 2;
      } else {
        player = 1;
      }

      const canvasMousePosition = getCanvasMousePosition(event);
      addPlayingPiece(canvasMousePosition);
      drawLines(10, lineColor);
    }
  };

  /** 依點擊位置決定繪製範圍 */
  const addPlayingPiece = (mouse) => {
    let xCordinate;
    let yCordinate;

    for (let x = 0; x < 3; x++) {
      for (let y = 0; y < 3; y++) {
        xCordinate = x * sectionSize;
        yCordinate = y * sectionSize;

        if (
          mouse.x >= xCordinate &&
          mouse.x <= xCordinate + sectionSize &&
          mouse.y >= yCordinate &&
          mouse.y <= yCordinate + sectionSize
        ) {
          /**  */
          clearPlayingArea(xCordinate, yCordinate);

          if (player === 1) {
            drawX(xCordinate, yCordinate);
          } else {
            drawO(xCordinate, yCordinate);
          }
        }
      }
    }
  };

  /** 畫圈圈 */
  const drawO = (xCordinate, yCordinate) => {
    const context = canvasRef.current.getContext("2d");
    const halfSectionSize = 0.5 * sectionSize;
    const centerX = xCordinate + halfSectionSize;
    const centerY = yCordinate + halfSectionSize;
    const radius = (sectionSize - 100) / 2;
    const startAngle = 0 * Math.PI;
    const endAngle = 2 * Math.PI;

    context.lineWidth = 10;
    context.strokeStyle = "#01bBC2";
    context.beginPath();
    context.arc(centerX, centerY, radius, startAngle, endAngle);
    context.stroke();
  };

  /** 畫叉叉 */
  const drawX = (xCordinate, yCordinate) => {
    const context = canvasRef.current.getContext("2d");
    context.strokeStyle = "#f1be32";

    context.beginPath();

    const offset = 50;
    context.moveTo(xCordinate + offset, yCordinate + offset);
    context.lineTo(
      xCordinate + sectionSize - offset,
      yCordinate + sectionSize - offset
    );

    context.moveTo(xCordinate + offset, yCordinate + sectionSize - offset);
    context.lineTo(xCordinate + sectionSize - offset, yCordinate + offset);

    context.stroke();
  };

  const drawLines = (lineWidth, strokeStyle) => {
    const context = canvasRef.current.getContext("2d");
    const lineStart = 4;
    const lineLenght = canvasSize - 5;
    context.lineWidth = lineWidth;
    context.lineCap = "round";
    context.strokeStyle = strokeStyle;
    context.beginPath();

    /*
     * Horizontal lines
     */
    for (let y = 1; y <= 2; y++) {
      context.moveTo(lineStart, y * sectionSize);
      context.lineTo(lineLenght, y * sectionSize);
    }

    /*
     * Vertical lines
     */
    for (let x = 1; x <= 2; x++) {
      context.moveTo(x * sectionSize, lineStart);
      context.lineTo(x * sectionSize, lineLenght);
    }

    context.stroke();
  };

  /** 清空畫布 */
  const clearPlayingArea = (xCordinate, yCordinate) => {
    if (canvasRef.current) {
      const context = canvasRef.current.getContext("2d");
      context.fillStyle = "#fff";
      context.fillRect(xCordinate, yCordinate, sectionSize, sectionSize);
    }
  };

  const getCanvasMousePosition = (event) => {
    const rect = canvasRef.current.getBoundingClientRect();
    return {
      x: event.clientX - rect.left,
      y: event.clientY - rect.top
    };
  };

  return (
    <div className="App">
      <div className="center-wrapper-parent">
        <div className="canvas-wrapper">
          <canvas
            width={canvasSize}
            height={canvasSize}
            ref={canvasRef}
            className="center-v"
            onMouseDown={handleMouseDown}
          ></canvas>
        </div>
      </div>
    </div>
  );
}


上一篇
Day 21 - canvas 玩拼圖 P5.js
下一篇
Day 23 - 用 canvas 與 requestAnimationFrame 做 進度條
系列文
Canvas 小錦囊30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言